package com.jevons.muffin.encrypt;


import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * DES3加解密
 * <p>
 * create at:  2016/8/25
 */
public class DES3Coder {

    //定义加密算法，有DES、DESede(即3DES)、Blowfish
    private static final String Algorithm = "DESede";

    /**
     * 字符串加密
     *
     * @param mStr     需要加密的字符串
     * @param password 用于生成Des3的秘钥（和解密保持一致--自定义，不能为空）
     * @return String
     */
    public static String encrypt(String password, String mStr) {
        if ((mStr == null) || ("".equals(mStr))) {
            return "";
        }
        return HexCoder.bytesToHexString(encryptMode(password, mStr.getBytes()));
    }

    /**
     * 加密方法
     *
     * @param src      源数据的字节数组
     * @param password 用于生成Des3的秘钥（和解密保持一致--自定义，不能为空）
     * @return byte[] 加密完的数据
     */
    public static byte[] encryptMode(String password, byte[] src) {
        try {
            //生成密钥
            SecretKey deskey = new SecretKeySpec(build3DesKey(password), Algorithm);
            //实例化负责加密/解密的Cipher工具类
            Cipher c1 = Cipher.getInstance(Algorithm);
            //初始化为加密模式
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            return c1.doFinal(src);
        } catch (java.security.NoSuchAlgorithmException e1) {
            throw new IllegalArgumentException("3DES生成SecretKey时找不到加解密算法," + e1.getMessage());
        } catch (javax.crypto.NoSuchPaddingException e2) {
            throw new IllegalArgumentException("3DES加解密算法的Padding不存在," + e2.getMessage());
        } catch (GeneralSecurityException e3) {
            throw new IllegalArgumentException("3DES加密异常," + e3.getMessage());
        }
    }

    /**
     * 字符串解密
     *
     * @param mStr     需要解密的字符串
     * @param password 用于解密Des3的秘钥密码（和加密保持一致--自定义，不能为空）
     * @return String
     */
    public static String decrypt(String password, String mStr) {
        if ((mStr == null) || ("".equals(mStr))) {
            return "";
        }
        return new String(decryptMode(password, HexCoder.hexStringToBytes(mStr))).trim();
    }

    /**
     * 解密函数
     *
     * @param src      密文的字节数组
     * @param password 用于解密Des3的秘钥密码（和加密保持一致--自定义，不能为空）
     * @return byte[] 解密完的数据
     */
    public static byte[] decryptMode(String password, byte[] src) {
        try {
            SecretKey deskey = new SecretKeySpec(build3DesKey(password), Algorithm);
            Cipher c1 = Cipher.getInstance(Algorithm);
            c1.init(Cipher.DECRYPT_MODE, deskey);    //初始化为解密模式
            return c1.doFinal(src);
        } catch (java.security.NoSuchAlgorithmException e1) {
            throw new IllegalArgumentException("3DES生成SecretKey时找不到加解密算法," + e1.getMessage());
        } catch (javax.crypto.NoSuchPaddingException e2) {
            throw new IllegalArgumentException("3DES加解密算法的Padding不存在," + e2.getMessage());
        } catch (GeneralSecurityException e3) {
            throw new IllegalArgumentException("3DES加密异常," + e3.getMessage());
        }
    }

    /*
     * 根据字符串生成密钥24位的字节数组
     * @param keyStr 密钥字符串
     * @return byte[] 秘钥24位字节数组
     */
    private static byte[] build3DesKey(String keyStr) {

        try {
            byte[] key = new byte[24];    //声明一个24位的字节数组，默认里面都是0
            byte[] temp = keyStr.getBytes("UTF-8"); //将字符串转成字节数组

            //执行数组拷贝
            //System.arraycopy(源数组，从源数组哪里开始拷贝，目标数组，拷贝多少位)
            if (key.length > temp.length) {
                //如果temp不够24位，则拷贝temp数组整个长度的内容到key数组中
                System.arraycopy(temp, 0, key, 0, temp.length);
            } else {
                //如果temp大于24位，则拷贝temp数组24个长度的内容到key数组中
                System.arraycopy(temp, 0, key, 0, key.length);
            }
            return key;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("3DES生成密钥时的编码格式不正确," + e.getMessage());
        }
    }

}
